/**
  ******************************************************************************
  * @file           : i_eeprom.c
  * @brief          : Internel eeprom operate middle layer code
  * @author         : Qilong Huang <jcdiyhelp@qq.com>
  * @date           : 2021-06-08 
  * 
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2021 Joy create tech(Suzhou, China) Co., Ltd.
  * All rights reserved.
  *
  *
  ******************************************************************************
  */
/* Global include ---------------------------------------------------------*/
#include "i_eeprom.h"

/* Global define ------------------------------------------------------------*/
UINT8_t BootInitSeedTemplete[4] = {0xAA, 0x55, 0xAA, 0x55};
UINT8_t BootLoaderVersionTemplete[12] = {'0', '0', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B'};
UINT8_t BootSecurityCodeTemplete[4] = {'0', '0', '1', '1'};
UINT32_t BootStatus = 0;
UINT32_t AppSWBiasCode = 0;
UINT32_t BakupSWBiasCode = 0;
UINT8_t  AppEmptyFlag = 0;
UINT32_t BackupEmptyFlag = 0;
UINT16_t RequireBCFlashFlag = TYP_FALSE;
UINT16_t RequireHalfProgram = TYP_TRUE;
UINT16_t BCFlashFinishedFlag = TYP_FALSE;

/* Global definition-------------------------------------------------------*/
UINT8_t BootInitSeed[4];
UINT8_t BootLoaderVersion[12];
UINT8_t BootSecurityCode[4];
TYP_InfoTab_t InfoTable[] = {
    /*index                     EepStartAddress  VarAddress                     SpaceLen                    Attribute */
    { BootInitFlagIndex,        0,               BootInitSeed,                   sizeof(BootInitSeed),        0x00},        //1.Boot init flag
    { BootVersionIndex,         4,               BootLoaderVersion,              sizeof(BootLoaderVersion),   0x00},        //2.Bootloader version
    { BootSecurityIndex,        16,              BootSecurityCode,               sizeof(BootSecurityCode),    0x00},        //3.Boot loader security code
    { BootStatusIndex,          24,              (UINT8_t*)&BootStatus,          sizeof(BootStatusIndex),     0x00},        //4.App bias code
    { AppSWBiasIndex,           28,              (UINT8_t*)&AppSWBiasCode,       sizeof(AppSWBiasCode),       0x00},        //4.App bias code
    { BakupSWBiasIndex,         32,              (UINT8_t*)&BakupSWBiasCode,     sizeof(BakupSWBiasCode),     0x00},        //5.Backup bias code
    { AppEmptyFlagIndex,        36,              (UINT8_t*)&AppEmptyFlag,        sizeof(AppEmptyFlag),        0x00},        //6.App bias code
    { BackupEmptyFlagIndex,     40,              (UINT8_t*)&BackupEmptyFlag,     sizeof(BackupEmptyFlag),     0x00},        //7.App bias code
    { RequireBCFlashIndex,      44,              (UINT8_t*)&RequireBCFlashFlag,  sizeof(RequireBCFlashFlag),  0x00},        //8.Require bootloader empty device flashing
    { RequireHalfProgramIndex,  46,              (UINT8_t*)&RequireHalfProgram,  sizeof(RequireHalfProgram),  0x00},        //9.Require flash half page programming
    { BCFlashFinishedFlagIndex, 48,              (UINT8_t*)&BCFlashFinishedFlag, sizeof(BCFlashFinishedFlag), 0x00},        //10. Bootloader empty device flashing finished
};

/**
 * @brief   Read bytes from EEPROM
 * @param   Addr   Start address you wanna to read, from 0~0xFFF(4096)
 * @return  Data read out
 */
UINT8_t I_EEPROM_ReadByte(UINT32_t Addr)
{
    TYP_MEMORY UINT32_t *wAddr;
    UINT8_t RetVal;
    if ((Addr >= I_EEPROM_BASE_ADDR) && (Addr <= I_EEPROM_MAX_LEN + I_EEPROM_BASE_ADDR))
    {
        wAddr = (UINT32_t *)(Addr);
        RetVal = (UINT8_t)*wAddr;
    }
    return RetVal;
}

/**
 * @brief   Write one byte to EEPROM
 * @param   Addr   Start address you wanna to write, from 0~0xFFF(4096)
 * @param   Data   Byte to write
 * @return  Function states
 */
TYP_funcRetrun_t I_EEPROM_WriteBytes(UINT32_t Addr, UINT8_t Data)
{
    TYP_MEMORY UINT8_t *wAddr;
    TYP_funcRetrun_t RetVal = TYP_FAIL;
    if ((Addr >= I_EEPROM_BASE_ADDR) && (Addr <= I_EEPROM_MAX_LEN + I_EEPROM_BASE_ADDR))
    {
        HAL_FLASHEx_DATAEEPROM_Unlock();
        HAL_FLASHEx_DATAEEPROM_Erase(FLASH_TYPEPROGRAMDATA_BYTE, Addr);
        HAL_FLASHEx_DATAEEPROM_Program( FLASH_TYPEPROGRAMDATA_BYTE,  Addr,  Data);
        if(I_EEPROM_ReadByte(Addr) != Data)
        {
            HAL_FLASHEx_DATAEEPROM_Program( FLASH_TYPEPROGRAMDATA_BYTE,  Addr,  Data);
        }
        if(I_EEPROM_ReadByte(Addr) != Data)
        {
            RetVal = TYP_FAIL;
        }
        else
        {
            RetVal = TYP_SUCCESS;
        }
        HAL_FLASHEx_DATAEEPROM_Lock();
    }
    return RetVal;
}

/**
 * @brief   Write n bytes to EEPROM
 * @param   OffsetAddress   Start address you wanna to write, from 0~0xFFF(4096)
 * @param   Buffer          Bytes buffer to write
 * @param   Length          Buffer size
 * @return  Function states
 */
TYP_funcRetrun_t I_EEPROM_WriteBuff(UINT32_t OffsetAddress, UINT8_t *Buffer, SINT8_t Length)
{
    SINT8_t len = Length;
    UINT8_t i = 0, Data;
    UINT32_t TempAddress;
    TYP_funcRetrun_t RetVal = TYP_SUCCESS, Status;
    HAL_FLASHEx_DATAEEPROM_Unlock();
    if((OffsetAddress >= 0) && (((OffsetAddress + Length) <= I_EEPROM_MAX_LEN)))
    {
        while(Length --)
        {
            TempAddress = I_EEPROM_BASE_ADDR + OffsetAddress + i;
            Data = *Buffer;
            //HAL_FLASHEx_DATAEEPROM_Erase(FLASH_TYPEPROGRAMDATA_BYTE, TempAddress);
            HAL_FLASHEx_DATAEEPROM_Program( FLASH_TYPEPROGRAMDATA_BYTE,  TempAddress,  Data);
            if(I_EEPROM_ReadByte(TempAddress) != Data)
            {
                HAL_FLASHEx_DATAEEPROM_Program( FLASH_TYPEPROGRAMDATA_BYTE,  TempAddress,  Data);
            }
            if(I_EEPROM_ReadByte(TempAddress) != Data)
            {
                RetVal = TYP_FAIL;
                break;
            }
            else
            {
                RetVal = TYP_SUCCESS;
                Buffer ++;
                i ++;
            }
        }
    }
    HAL_FLASHEx_DATAEEPROM_Lock();
    return RetVal;
}

/**
 * @brief   Read bytes from EEPROM
 * @param   OffsetAddress   Start addre
 * @param   Buffer          Bytes buffe
 * @param   Length          Buffer size
 * @return  Data read out
 */
TYP_funcRetrun_t I_EEPROM_ReadBuffer(UINT32_t OffsetAddress, UINT8_t *Buffer, SINT8_t Length)
{
    TYP_MEMORY UINT8_t *wAddr = NULL;
    TYP_funcRetrun_t RetVal = TYP_SUCCESS;
    TYP_MEMORY UINT32_t TempAddress = 0;
    TYP_MEMORY UINT8_t i = 0;
    if((OffsetAddress >= 0) && (((OffsetAddress + Length) <= I_EEPROM_MAX_LEN)))
    {
        while(Length --)
        {
            TempAddress = I_EEPROM_BASE_ADDR + OffsetAddress + i;
            wAddr = (UINT8_t *)(TempAddress);
            *Buffer = *wAddr;
            i ++;
            Buffer ++;
        }
    }
    return RetVal;
}

/**
  * @brief Parameter Initialization Function
  * @param None
  * @retval None
  */
void I_EEPROM_ParaInit(void)
{
    I_EEPROM_ReadBuffer(InfoTable[BootInitFlagIndex].EepStartAddress, (UINT8_t *)BootInitSeed, 4);
    if(BootInitSeed[0] != 0xAA && BootInitSeed[1] != 0x55 && BootInitSeed[2] != 0xAA && BootInitSeed[3] != 0x55)
    {
        I_EEPROM_WriteBuff(InfoTable[BootInitFlagIndex].EepStartAddress, (UINT8_t *)BootInitSeedTemplete, InfoTable[BootInitFlagIndex].SpaceLen);
        I_EEPROM_WriteBuff(InfoTable[BootVersionIndex].EepStartAddress, (UINT8_t *)BootLoaderVersionTemplete, InfoTable[BootVersionIndex].SpaceLen);
        I_EEPROM_WriteBuff(InfoTable[BootSecurityIndex].EepStartAddress, (UINT8_t *)BootSecurityCodeTemplete, InfoTable[BootSecurityIndex].SpaceLen);
        I_EEPROM_WriteBuff(InfoTable[BootStatusIndex].EepStartAddress, (UINT8_t *)&BootStatus, InfoTable[BootStatusIndex].SpaceLen);
        I_EEPROM_WriteBuff(InfoTable[AppSWBiasIndex].EepStartAddress, (UINT8_t *)&AppSWBiasCode, InfoTable[AppSWBiasIndex].SpaceLen);
        I_EEPROM_WriteBuff(InfoTable[BakupSWBiasIndex].EepStartAddress, (UINT8_t *)&BakupSWBiasCode, InfoTable[BakupSWBiasIndex].SpaceLen);
        I_EEPROM_WriteBuff(InfoTable[AppEmptyFlagIndex].EepStartAddress, (UINT8_t *)&AppEmptyFlag, InfoTable[AppEmptyFlagIndex].SpaceLen);
        I_EEPROM_WriteBuff(InfoTable[BackupEmptyFlagIndex].EepStartAddress, (UINT8_t *)&BackupEmptyFlag, InfoTable[BackupEmptyFlagIndex].SpaceLen);

        I_EEPROM_ReadBuffer(InfoTable[BootInitFlagIndex].EepStartAddress, (UINT8_t *)InfoTable[BootInitFlagIndex].VarAddress, InfoTable[BootInitFlagIndex].SpaceLen);
        I_EEPROM_ReadBuffer(InfoTable[BootVersionIndex].EepStartAddress, (UINT8_t *)InfoTable[BootVersionIndex].VarAddress, InfoTable[BootVersionIndex].SpaceLen);
        I_EEPROM_ReadBuffer(InfoTable[BootSecurityIndex].EepStartAddress, (UINT8_t *)InfoTable[BootSecurityIndex].VarAddress, InfoTable[BootSecurityIndex].SpaceLen);
        I_EEPROM_ReadBuffer(InfoTable[BootStatusIndex].EepStartAddress, (UINT8_t *)&BootStatus, InfoTable[BootStatusIndex].SpaceLen);
        I_EEPROM_ReadBuffer(InfoTable[AppSWBiasIndex].EepStartAddress, (UINT8_t *)&AppSWBiasCode, InfoTable[AppSWBiasIndex].SpaceLen);
        I_EEPROM_ReadBuffer(InfoTable[BakupSWBiasIndex].EepStartAddress, (UINT8_t *)&BakupSWBiasCode, InfoTable[BakupSWBiasIndex].SpaceLen);
        I_EEPROM_ReadBuffer(InfoTable[AppEmptyFlagIndex].EepStartAddress, (UINT8_t *)&AppEmptyFlag, InfoTable[AppEmptyFlagIndex].SpaceLen);
        I_EEPROM_ReadBuffer(InfoTable[BackupEmptyFlagIndex].EepStartAddress, (UINT8_t *)&BackupEmptyFlag, InfoTable[BackupEmptyFlagIndex].SpaceLen);
    }
    else
    {
        I_EEPROM_ReadBuffer(InfoTable[BootInitFlagIndex].EepStartAddress, (UINT8_t *)InfoTable[BootInitFlagIndex].VarAddress, InfoTable[BootInitFlagIndex].SpaceLen);
        I_EEPROM_ReadBuffer(InfoTable[BootVersionIndex].EepStartAddress, (UINT8_t *)InfoTable[BootVersionIndex].VarAddress, InfoTable[BootVersionIndex].SpaceLen);
        I_EEPROM_ReadBuffer(InfoTable[BootSecurityIndex].EepStartAddress, (UINT8_t *)InfoTable[BootSecurityIndex].VarAddress, InfoTable[BootSecurityIndex].SpaceLen);
        I_EEPROM_ReadBuffer(InfoTable[BootStatusIndex].EepStartAddress, (UINT8_t *)&BootStatus, InfoTable[BootStatusIndex].SpaceLen);
        I_EEPROM_ReadBuffer(InfoTable[AppSWBiasIndex].EepStartAddress, (UINT8_t *)&AppSWBiasCode, InfoTable[AppSWBiasIndex].SpaceLen);
        I_EEPROM_ReadBuffer(InfoTable[BakupSWBiasIndex].EepStartAddress, (UINT8_t *)&BakupSWBiasCode, InfoTable[BakupSWBiasIndex].SpaceLen);
        I_EEPROM_ReadBuffer(InfoTable[AppEmptyFlagIndex].EepStartAddress, (UINT8_t *)&AppEmptyFlag, InfoTable[AppEmptyFlagIndex].SpaceLen);
        I_EEPROM_ReadBuffer(InfoTable[BackupEmptyFlagIndex].EepStartAddress, (UINT8_t *)&BackupEmptyFlag, InfoTable[BackupEmptyFlagIndex].SpaceLen);
        AppSWBiasCode = FLASH_ReadWord(AppBISAddress);
        BakupSWBiasCode = FLASH_ReadWord(BackBISAddress);
    }
}
